#include "StdAfx.h"
#include "SceneNode.h"

#include "SceneManager.h"
#include "Movable.h"
#include "Camera.h"
#include "Renderer.h"

using namespace RenderSystem;

SceneNode::SceneNode( SceneManager* pCreator )
	:m_pCreator(pCreator)
{
}


SceneNode::~SceneNode(void)
{
}

void SceneNode::SetParent(Node* pParent)
{
	Node::SetParent(pParent);

	if( pParent != NULL )
	{
		SceneNode* sceneParent = static_cast<SceneNode*>( pParent );
		SetInSceneGraph( sceneParent->IsInSceneGraph() );
	}
	else
		SetInSceneGraph(false);
}
//-----------------------------------------------------------------------
void SceneNode::SetInSceneGraph( bool bInGraph )
{
	if( bInGraph != m_bInGraph )
	{
		m_bInGraph = bInGraph;
		IteratorChildNode itrObject = m_Children.begin();
		for( ; itrObject != m_Children.end(); ++itrObject )
		{
			SceneNode* pChild = static_cast<SceneNode*>(*itrObject);
			pChild->SetInSceneGraph( bInGraph );
		}
	}
}

void SceneNode::AttachObject( Movable* pMovableObject )
{
	//check the attached object is unified
	if( pMovableObject == NULL )
		return;

	if( std::find( m_conMovableObjects.begin(), m_conMovableObjects.end(), pMovableObject ) == m_conMovableObjects.end() )
		return;

	m_conMovableObjects.push_back( pMovableObject );

	pMovableObject->AttachTo( this );
}

uint32 SceneNode::GetAttachedObjectsCount(void) const
{
	return m_conMovableObjects.size();
}

Movable* SceneNode::GetAttachedObject( uint32 uObjIdx )
{
	if( uObjIdx >= m_conMovableObjects.size() )
		return NULL;

	return m_conMovableObjects[uObjIdx];
}

Movable* SceneNode::DetachObject( uint32 uObjIdx )
{
	Movable* pMovable = this->GetAttachedObject( uObjIdx );
	if( pMovable == NULL )
		return NULL;

	this->DetachObject( pMovable );
	
	return pMovable;
}

void SceneNode::DetachObject( Movable* pObj )
{
	ObjectIterator pos = std::find( m_conMovableObjects.begin(), m_conMovableObjects.end(), pObj );
	if( pos == m_conMovableObjects.end() )
		return;
	m_conMovableObjects.erase( pos );

	pObj->AttachTo( NULL );
}

void SceneNode::DetachAllObjects(void)
{
	std::for_each( m_conMovableObjects.begin(), m_conMovableObjects.end(), std::bind2nd( std::mem_fun1( Movable::AttachTo ), NULL ) );

	m_conMovableObjects.clear();
}

void SceneNode::ShowBoundingBox(bool bShow)
{
	m_bShowAABBWireFrame = bShow;
}

bool SceneNode::GetShowBoundingBox() const
{
	return m_bShowAABBWireFrame;
}

SceneNode* SceneNode::CreateChildSceneNode( const Common::Vector3& translate ,  const Common::Quaternion& rotate )
{
	Node* pNewNode = Node::CreateChild( translate, rotate );
	return static_cast<SceneNode*>( pNewNode );
}

SceneNode* SceneNode::GetParentSceneNode(void) const
{
	Node* pParent = Node::GetParent();
	return static_cast<SceneNode*>( pParent );
}

void SceneNode::SetVisible( bool visible, bool cascade )
{
	std::for_each( m_conMovableObjects.begin(), m_conMovableObjects.end(), std::bind2nd( std::mem_fun1( Movable::SetVisible ), visible ) );

	if( cascade )
	{
		IteratorChildNode pos = m_Children.begin();
		for( ; pos != m_Children.end(); ++pos )
		{
			SceneNode* pChild = static_cast< SceneNode* >(*pos);
			pChild->SetVisible( visible, cascade );
		}
	}
}

void SceneNode::_Update(bool updateChildren, bool parentHasChanged)
{
	Node::_Update( updateChildren, parentHasChanged );
	this->_UpdateBounds();
}

void SceneNode::_UpdateBounds(void)
{
	m_WorldAABB.setNull();

	ObjectIterator itrMoveObject = m_conMovableObjects.begin();
	for( ; itrMoveObject != m_conMovableObjects.end(); ++itrMoveObject )
		m_WorldAABB.merge( (*itrMoveObject)->GetBoundingBox(true) );
}

void SceneNode::FindVisibleObjects( Camera* pCamera, Renderer* pRender, bool bIncludeChildren )
{
	if( !pCamera->CheckVisible( this ) )
		return;
	
	ObjectIterator itrMovable = m_conMovableObjects.begin();
	for( ; itrMovable != m_conMovableObjects.end(); itrMovable++ )
	{
		Renderable* pRenderableObject = dynamic_cast< Renderable* >( *itrMovable );
		if( pRenderableObject == NULL )
			continue;
		pRender->AddRenderable( pRenderableObject );
	}

	//recursive for each child
	if( !bIncludeChildren )
		return;

	IteratorChildNode itrChild = m_Children.begin();
	for( ; itrChild != m_Children.end(); ++itrChild )
	{
		SceneNode* pSceneNodeChild = static_cast< SceneNode* >(*itrChild);
		pSceneNodeChild->FindVisibleObjects( pCamera, pRender, bIncludeChildren );
	}
}
